Linguaggio C

 

per collaborazioni, commenti, critiche, e altro contattateci alla e-mail: clubinfo@libero.it risponderemo al più presto!

Funzioni di input/output

di Luca Sabatucci

Lezione 11

Pagina principale | Lezione precedente | Lezione successiva


Funzione printf

Abbiamo usato le funzioni di input e output praticamente in gni file di esempio proposto fino ad ora lasciando come commento un semplice "mediante queste funzioni si richiede in ingresso un dato all'utente" oppure "si stampa su schermo" ma abbiamo sempre rimandato a questa lezione una spiegazione più dettagliata.
Adesso vedremo come interagire con le periferiche standard del nostro PC: la tastiera e il monitor. In una lezione successiva vedremo come interagire con altre periferiche come dischi e stampanti.

La funzione printf esegue l'operazione di output formattato su monitor. Si tratta di una funzione definita nella libreria stdio, il cui prototipo si trova nel file stdio.h che abbiamo sempre incuso nei nostri sorgenti.

Il prototipo della funzione è:

int printf (const char *stringa_di_controllo, ...);

La prima funzione che vediamo utilizza delle caratteristiche non standard del linguaggio, infatti i tre puntini come argomento dei parametri indicano che si può inserire un numero arbitrario di parametri (cosa che abbiamo visto non si può fare per le funzioni normali del C).

Il modo più semplice per usare la printf è con la sola stringa da stampare:

printf("Ciao mondo");

Il risultato su schermo è la stampa della stringa:

Ciao mondo

Specificatori

La stringa di controllo contiene la descrizione di ciò che deve essere visualizzato sullo schermo: questo può essere una semplice stringa (come nel caso precendente) oppure un output più complesso che dipende dal valore di certi parametri. Questo viene fatto inserendo nella stringa di controllo degli "specificatori" (ad esempio: %d) i quali non vengono stampati così per come sono, ma ad essi viene sostituito il valore di una espressione ripostata come parametro della printf.
Un esempio più complesso utilizza lo specificatore %d:

printf("risultato: %d",var);

lo specificatore %d stampa un numero decimale; nel nostro caso viene stampato il valore della variabile var. L'output di questa istruzione, supponendo che var=25 è:

risultato: 25

Per ogni specificatore di formato nella stringa di controllo deve essere presente un parametro aggiuntivo da sostituire.
Altro esempio:

printf("%d+%d=%d",a,b,a+b);

presenta tre specificatori e altrettanti parametri oltre la stringa di controllo.
Questa istruzione stampa su schermo (se a=4 e b=7):

4+7=11

Vediamo quali sono gli specificatori di formato che è possibile usare:

specificatore significato
%c carattere
%d interi decimali con segno
%i interi decimali con segno
%e notazione scientifica (e minuscola)
%E notazione scientifica (E maiuscola)
%f numero decimale in virgola mobile
%g usa il più corto tra %e e %f
%G usa il più corto tra %E e %f
%o ottale senza segno
%s stringa di caratteri
%u interi decimali senza segno
%x esadecimale senza segno (lettere minuscole)
%X esadecimale senza segno (lettere maiuscole)
%p visualizza un puntatore
%% stampa il carattere %

Facciamo alcuni esempi e riportiamo di seguito l'output previsto.

double radice=12.34;
int numero=59;
char stringa[]="Oggi e' il 22 Ottobre 2000";

printf("virgola mobile: %f, notazione scientifica: %e \n",radice,radice);

printf("base 10: %d \n",numero);
printf("base 8 : %o \n",numero);
printf("base 16: %X \n",numero);

printf("%s \n",stringa);
virgola mobile: 12.340000, notazione scientifica: 1.23400e+01
base 10: 59
base 8 : 73
base 16: 3B
Oggi e' il 22 Ottobre 2000

Come si vede si è inserito nelle stringhe anche un altro elemento: \n. Si tratta del codice usato per inserire un newline, usato per scrivere sulla riga successiva. Se non specificato la funzione printf non manda a capo neppure al termina della stringa. Ad esempio il frammento di codice seguente:

printf("Luca");
printf("Sabatucci");

Non produce l'output

Luca
Sabatucci

ma piuttosto

LucaSabatucci

L'inserimento del newline è possibile in un punto qualunque della stringa di controllo. Ecco un esempio:

printf("Luca\nSabatucci");
printf("Sabatucci");

Produce esattamente l'output voluto in precedenza:

Luca
Sabatucci

Caratteri speciali

Oltre al newline ci sono altri caratteri speciali che è possibile stampare inserendo nella stringa una combinazione speciale formata sempre dal carattere slash '\' e da un carattere successivo. Ecco un elenco di tali combinazioni:

codice significato
\b backspace
\f formfeed
\n new line
\r carriage return
\t tabulazione
\" doppi apici
\' apici
\0 carattere nullo
\\ backslash

Come si può notare alcune di queste servono ad inserire dei caratteri che altrimenti non sarebbe possibile inserire perchè sono usati nella sintassi del C. E' il caso dei doppi apici " che vengono usati per delimitare inizio e fine della costante stringa.

Specificatore di minima ampiezza

La funzione printf è una funzione estremamente evoluta e permette di stampare del testo formattato. Questo vuol dire che è possibile controllare abbastanza in dettaglio l'output fornito.

Lo specificatore di minima ampiezza indica che un determinato campo dovrà assumere la largezza minima specificata; se i caratteri stampati dovessero essere di meno di quelli voluti, verrà automaticamente aggiunti degli spazi (o un carattere specificato). Nessuna modifica viene invece apportata a numeri e stringhe più grandi. Lo specificatore di ampiezza minima viene effettuato inserendo tra il % e il carattere successivo il numero di ampiezza voluta.

Esempio:

int num = 18;

printf("%dsemplice \n",num);
printf("%4dcon ampiezza 4 \n",num);

mostra come output:


18semplice
18  con ampiezza 4

Per aggiungere un carattere diverso dallo spazio, questo deve essere specificato prima del numero che indica l'ampiezza.

Esempio:

int num = 18;

printf("%*4d",num);

mostra come output:
18**

Come sottolineato da Herbert Schildt lo specificatore di ampiezza minima di un campo è usato principalmente per produrre tabelle con colonne allineate. Riporto l'esempio da egli stesso utilizzato:

int i;

for (i=1; i<20; i++)
	printf("%8d %8d %8d\n",i,i*i,i*i*i);

e qui c'è l'ouput:


       1        1        1
       2        4        8
       3        9       27
       4       16       64
       5       25      125
       6       36      216
       7       49      343
       8       64      512

Specificatore di precisione

Il formato dello specificatore di precisione è un punto '.' seguito da un numero intero. Se viene applicato ad un numero in virgola mobile (esempio %.4f oppure %.8E) determina il numero di cifre decimali visualizzate. Può essere usato anche in combinazione con lo specificatore di ampiezza minima. Ad esempio %10.4f stampa un numero in virgola mobile con assegnando almeno 10 caratteri e 4 cifre decimali.

Applicato alle stringhe indica invece la lunghezza massima del campo. Ad esempio %5.7s visualizza una stringa con minimo 5 caratteri e massimo 7.

Applicato ai numeri interi indica la lunghezza complessiva del numero stampato inserendo degli zeri iniziali per arrivare alla lunghezza voluta. Ad esempio "%2.5d",10 stampa 00010.

Allineamento

Normalmente se il campo ha una ampiezza minima superiore a quella dei caratteri da stampare, questi vengono allineati a destra; si veda l'esempio della tabella di sopra.
Si può richiedere l'allineamento a sinistra inserendo il segno meno subito dopo il segno di percento '%'; esempio %-5d. La stessa tabella verrebbe stampata così:


1        1        1
2        4        8
3        9        27
4        16       64
5        25       125
6        36       216
7        49       343
8        64       512
9        81       729

La printf restituisce un valore

Per concludere la nostra analisi della printf notiamo, dal prototipo presentato all'inizio, che la funzione restituisce un valore intero. Il valore restituito comunica il numero di carattere stampati, e sebbene non è sempre utilissimo, a volte può servire per effettuare delle stampe ordinate.

Funzione scanf

La funzione scanf è la controparte della printf per la richiesta di dati attraverso la tastiera. Si tratta di una funzione molto complessa e che permette di effettuare molto facilmente riconoscimenti sintattici.

Il prototipo della scanf (che si trova nel file stdio.h) è:

int scanf(const char *stringa_di_controllo, ...)

Come la printf, anche la scanf presenta un numero di parametri in ingresso non definito, da usare con la stessa logica di prima: nella stringa di controllo si determina quale input è richiesto e nelle variabili successive verrà posto il valore digitato.

Nella stringa di controllo è possibile inserire specificatori, e caratteri normali. Ecco un esempio piuttosto complesso che andremo analizzando: "%s %s; %d" usato per inserire nome, cognome e età di una persona con una sintassi di questo tipo: "Luca Sabatucci; 24"

Specificatori

Presentiamo di seguito l'elenco degli specificatori con un breve commento:

codice significato
%c legge un carattere
%d legge un intero decimale
%i legge un intero decimale
%e legge un numero in virgola mobile
%f legge un numero in virgola mobile
%g legge un numero in virgola mobile
%o legge un numero ottale
%s legge una stringa
%x legge un numero esadecimale
%p legge un puntatore
%nu legge un intero senza segno
%[] attende l'immissione di un determinato insieme di caratteri

Facciamo alcuni esempi, del modo più comune di usare la scanf. In genere prima della scanf si usa una printf nella quale si spiega cosa deve essere digitato.

printf("inserisci la tua eta'");
scanf("%d",&eta);

printf("inserisci il tuo nome");
scanf("%s",nome);

printf("inserisci la tua altezza");
scanf("%i",&altezza);

Il parametro da inserire dopo la striga di controllo deve essere la variabile in cui memorizzare il risultato dell'input. Come abbiamo studiato in precedenza il passaggio dei parametri in una funzione è fatto sempre per valore (cioè si passa una copia della variabile e non la variabile stessa). Ciò significa che se scrivessi scanf("%i",altezza); all'interno della funzione non ci sarebbe alcun modo per cambiare il valore di altezza. Per questo motivo è necassario passare l'indirizzo della variabile, in modo che le modifiche siano valide. Questo argomento lo riprenderemo tra breve quando tratteremo i puntatori. Per il momento basta ricordare di premettere il carattere e-commerciale '&' prima del nome della variabile (che abbiamo visto essere l'operatore che restituisce l'indirizzo di una variabile).

Vorrei fare notare che nell'esempio c'è anche una eccezione: la stringa viene immessa senza l'operatore &. Questo viene fatto per un motivo ben preciso che analizzeremo in seguito. Per adesso dico soltanto che nome è gia' un puntatore alla stringa.

Gruppi di scansione

Si tratta di una delle potenzialità del comando scanf. Il gruppo di scansione definisce un gruppo di caratteri che sono validi come input. Solo i caratteri corrispondenti saranno validi e sono passati ad una stringa. La stringa restituita sarà terminata da un carattere nullo. I caratteri che fanno parte del gruppo di scansione sono quelli racchiusi tra le parentesi graffe; esempio %[abc] oppure %[YN].

La scanf continua a leggere i caratteri che fanno parte del gruppo di scansione finchè non si incontra un carattere estraneo; tutti i caratteri seguenti saranno ignorati. In ogni caso l'input finisce quando si preme invio.

Come esempio riporto uno preso dallo Herbert Schildt:

#include <stdio.h>

void main() {
	int i;
	char str[80],str2[80]:

	scanf("%d%[abcdefg]%s",&i,str,str2);
	printf("%d %s %s",i,str,str2);
}	

Immettendo 123abcdtype e premendo INVIO, il programma visualizza 123 abcd type. Infatti poichè t non appartiene al gruppo di scansione, esso non viene assegnato a str e la scansione del gruppo termina. Poichè in seguito si richiede l'immissione di una stringa il resto della digitazione viene trasferito nella stringa.

Caratteri nella stringa di controllo

Abbiamo detto che nella string adi controllo si possono inserire anche dei caratteri diversi dagli specificatori. A differenza di quanto si possa credere questi non vengono visualizzati, ma hanno un funzione diversa. Spieghiamo tutto con un esempio:

printf("inserisci la data di nascita giorno/mese/anno");
scanf("%d/%d/%d",&giorno,&mese,&anno);

Quando viene digiatato 16/02/76 i caratteri '/' inseriti tra gli specificatori vengono attesi ma ignorati. Se venisse inserita la data come 160276 la scanf terminerebbe in modo non corretto.

Inoltre esiste un modo per sopprimere qualcosa che p stato letto in input e che non serve. Si tratta dello specificatori di soppressione del campo. Se uno specificatore viene preceduto dal carattere asterisco '*' il campo viene letto ma il valore non viene assegnato a nessuna variabile. Ad esempio la data può essere richiesta con la stringa di controllo:

printf("inserisci la data di nascita giorno/mese/anno");
scanf("%d*%c%d*%c%d",&giorno,&mese,&anno);

In questo caso se viene digitato 16.02.76 la scanf accetta ugualmente il formato!

Riprendiamo quindi l'esempio fatto in precedenza:

printf("inserisci nome, cognome e eta' nel formato [nome cognome; eta']");
scanf("%s %s; %d",nome,cognome,&eta);

In questo caso nella stessa riga è possibile digitare Luca Sabatucci; 24 e immediatamente, senza alcun intervento del programatore ogni informazione viene collocata al posto giusto.

Specificatore di ampiezza massima del campo

Anche in questo caso è possibile limitare la lunghezza massima dei caratteri immessi nel campo. Questo si effettua inserendo un intero tra il carettere '%' e il carattere che individua il tipo di dato. Esempio:

printf("inserisci l'indirizzo");
scanf("%30s",indirizzo);

Non a caso l'esempio riporta il caso di una stringa, infatti è questo il caso più comune in cui si usa tale specificatore. Le stringhe infatti, abbiamo visto, sono array di caratteri, la cui dimensione viene prefissata in fase di dichiarazione. Poichè non è possibile prevedere la quantità di caratteri che l'utente vuole digitare, si può porre un limite a tale numero in modo che non si vada a "sporcare" zone di memoria esterne all'array.


Bibliografia


Testi consigliati per l'apprendimento

Questo articolo è stato scaricato dal Club di informatica
Pagina curata da Luca Sabatucci